package top.jnaw.test.util.plugin;

import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import top.jnaw.test.model.RolesPermissions;
import top.jnaw.test.model.UserRoles;
import top.jnaw.test.model.Users;

public class Shiros {

  private static boolean isUseSalt = PropKit.get("shiro_use_salt").equals("true");
  private static String SEPARATOR = ":";
  private static String SQL_ADD_USER = "INSERT IGNORE INTO users"
      + " (username, password, password_salt) VALUES (?, ?, ?)";
  private static String SQL_SET_USER = "UPDATE users"
      + " SET password = ?, password_salt = ? WHERE username = ?";

  private static String SQL_DELETE_USER = "DELETE FROM users"
      + " WHERE username = ?";

  private static String SQL_CLEAN_ROLES = "DELETE FROM user_roles"
      + " WHERE username = ?";
  private static String SQL_CLEAN_PERMISSIONS = "DELETE FROM roles_permissions"
      + " WHERE role_name = ?";

  private static String SQL_SET_ROLES = "INSERT IGNORE INTO user_roles"
      + " (username, role_name) VALUES (?, ?)";
  private static String SQL_SET_PERMISSIONS =
      "INSERT IGNORE INTO roles_permissions"
          + " (role_name, permission) VALUES (?, ?)";

  private static String SQL_GET_ROLES = "SELECT role_name"
      + " FROM user_roles WHERE username = ?";
  private static String SQL_GET_PERMISSIONS = "SELECT permission"
      + " FROM roles_permissions WHERE role_name = ?";

  static {

  }




  /**
   * 根据用户名查询用户信息
   */
  public static Users findUserByLoginName(String loginName,String password) {

    String sql = "select * from users where username = ? ";
    List<Users> usersList = Users.dao.find(sql,loginName);
    Users users=null;
    if (usersList.size()>0){
      users=usersList.get(0);
    }
    return users;

  }

  /**
   * 根据用户名获取用户角色的名字列表
   */
  public static List<String> getRoleNameList(String loginName) {
    List<String> stringList = new ArrayList<>();
    String sql = "select * from user_roles where username = ? ";
    List<UserRoles> userRoles = null;

    userRoles = UserRoles.dao.find(sql, loginName);
    for (UserRoles userRoles1 : userRoles) {
      stringList.add(userRoles1.getRoleName());
    }
    return stringList;
  }

  /**
   * 根据用户名获取用户角色列表
   */
  public static List<UserRoles> getRoleList(String loginName) {
    String sql = "select * from user_roles where username = ? ";
    List<UserRoles> userRoles = null;
    userRoles = UserRoles.dao.find(sql, loginName);
    return userRoles;
  }

  /**
   * 根据角色名查询权限列表
   */
  public static List<String> getPermissionNameListByRole(String rolename) {
    String sql = "select * from roles_permissions where role_name = ?";
    List<RolesPermissions> listrp = RolesPermissions.dao.find(sql, rolename);
    List<String> list = new ArrayList<>();
    for (RolesPermissions rp : listrp) {
      list.add(rp.getPermission());
    }
    return list;
  }

  /**
   * 添加一个新用户
   */
  public static boolean addUser(String username, String password) {
    boolean result = false;
    int rows = Db
        .update(SQL_ADD_USER, username, isUseSalt ? hashPassword(username, password) : password,
            genSalt(username));
    result = (1 == rows);
    return result;
  }

  /**
   * 修改用户密码
   *
   * @param password 新密码
   * @return 是否成功
   */
  public static boolean setPwd(String username, String password) {
    boolean result = false;
    int rows = Db
        .update(SQL_SET_USER, isUseSalt ? hashPassword(username, password) : password, username);
    result = (1 == rows);
    return result;
  }

  /**
   * 删除用户
   *
   * @return 是否成功
   */
  public static boolean deleteUser(String username) {
    boolean result = false;
    int rows = Db.update(SQL_DELETE_USER, username);
    result = (1 == rows);
    return result;
  }

  /**
   * 更新用户所属角色
   * @return 是否成功
   */
  public static boolean setRoles(String user, String... roles) {
    return update(SQL_CLEAN_ROLES,SQL_SET_ROLES,user,roles);
  }
  /**
   * 更新角色的权限
   *
   * @return 是否成功
   */
  public static boolean setPermissions(String role, String... permissions) {
    return update(SQL_CLEAN_PERMISSIONS,SQL_SET_PERMISSIONS,role,permissions);
  }

  /**
   * 更新用户所属角色
   *
   * @return 是否成功
   */
  public static boolean setRoles(String user, List<String> roles) {
    return update(SQL_CLEAN_ROLES, SQL_SET_ROLES, user, roles.toArray(new String[0]));
  }

  /**
   * 更新角色的权限
   *
   * @return 是否成功
   */
  public static boolean setPermissions(String role, List<String> permissions) {
    return update(SQL_CLEAN_PERMISSIONS, SQL_SET_PERMISSIONS, role, permissions.toArray(new String[0]));
  }

  /**
   * 登录
   *
   * @param remember 是否记住用户名和密码
   * @return 是否正确
   */
  public static boolean login(String user, String pwd,
      boolean remember) {
    boolean result = false;
    Subject subject = SecurityUtils.getSubject();
    if (null != subject) {
      pwd =isUseSalt ? hashPassword(user, pwd) : pwd;
      UsernamePasswordToken token = new UsernamePasswordToken(user, pwd);
      token.setRememberMe(remember);
      try {
        subject.login(token);
        result = true;
      } catch (Exception e) {
        // [Neo] Empty
      }
    }

    return result;
  }

  /**
   * 登录
   */
  public static boolean login(String user, String pwd) {
    return login(user, pwd, false);
  }

  /**
   * 登出
   */
  public static boolean logout() {
    boolean result = false;

    Subject subject = SecurityUtils.getSubject();
    if (null != subject) {
      subject.logout();
    }
    return result;
  }

  /**
   * 当前用户是否已经登录
   *
   * @return 是否登录
   */
  public static boolean isAuthc() {
    boolean result = false;

    Subject subject = SecurityUtils.getSubject();
    if (null != subject) {
      result = subject.isAuthenticated();
    }

    return result;
  }

  /**
   * 获取通过 Shiros 验证登录的用户名
   */
  public static String getUser() {
    String user = null;

    Subject subject = SecurityUtils.getSubject();
    if (null != subject) {
      final Object p = subject.getPrincipal();
      if (null != p) {
        user = p.toString();
      }
    }

    return user;
  }
  /**
   * 当前用户是否属于某个角色
   *
   * @return 是否属于
   */
  public static boolean hasRole(String role) {
    boolean result = false;
    Subject subject = SecurityUtils.getSubject();

    if (null != subject && StrKit.notBlank(role)) {
      result = subject.hasRole(role);
    }

    return result;
  }

  /**
   * 当前用户是否属于某一些角色
   *
   * @return 是否属于
   */
  public static boolean[] hasRoles(List<String> roles) {
    boolean[] results = null;
    Subject subject = SecurityUtils.getSubject();

    if (null != subject && null != roles) {
      results = subject.hasRoles(roles);
    }

    return results;
  }

  /**
   * 当前用户是否属于某一些角色
   *
   * @return 是否属于
   */
  public static boolean[] hasRoles(String... roles) {
    boolean[] results = null;
    Subject subject = SecurityUtils.getSubject();

    if (null != subject && null != roles) {
      List<String> list = new ArrayList<>();
      for (String r : roles) {
        list.add(r);
      }

      results = subject.hasRoles(list);
    }

    return results;
  }

  /**
   * 当前用户是否具备某个权限
   *
   * @return 是否具备权限
   */
  public static boolean isPermitted(String permission) {
    boolean result = false;
    Subject subject = SecurityUtils.getSubject();

    if (null != subject && StrKit.notBlank(permission)) {
      result = subject.isPermitted(permission);
    }

    return result;
  }

  /**
   * 当前用户是否具备某些权限
   *
   * @return 是否具备权限
   */
  public static boolean[] isPermitted(List<String> permissions) {
    boolean[] results = null;
    Subject subject = SecurityUtils.getSubject();

    if (null != subject && null != permissions) {
      String[] p = new String[permissions.size()];
      for (int i = 0; i < p.length; ++i) {
        p[i] = permissions.get(i);
      }

      results = subject.isPermitted(p);
    }

    return results;
  }

  /**
   * 当前用户是否具备某些权限
   *
   * @return 是否具备权限
   */
  public static boolean[] isPermitted(String... permissions) {
    boolean[] results = null;
    Subject subject = SecurityUtils.getSubject();

    if (null != subject && null != permissions) {
      results = subject.isPermitted(permissions);
    }

    return results;
  }

  /**
   * setRoles
   * setPermissions
   * 公共操作数据库方法
   */
  public static boolean update(String deleteSql, String updateSql,
      String param, String... array) {
    return Db.tx(new IAtom() {
      @Override
      public boolean run() throws SQLException {
        Db.update(deleteSql, param);
        boolean saveDataResult = true;

        for (String c : array) { //循环遍历
          saveDataResult = saveDataResult
              && Db.update(SQL_SET_ROLES, param, c) == 1; //将所有结果与，只要有一条失败就跳出循环，返回false
          if (!saveDataResult) {
            break;
          }
        }
        return saveDataResult;
      }
    });

  }


  /**
   * 根据指定的算法、原文、盐值以及次数计算哈希值
   *
   * @param algorithm 算法
   * @param source 原文
   * @param salt 盐
   * @param iterations 次数
   * @return 哈希结果
   */
  public static String hashWithSalt(String algorithm, String source,
      String salt, int iterations) {
    return new SimpleHash(algorithm, source, salt, iterations).toHex();
  }

  /**
   * 根据原文和盐值计算哈希值，算法和次数依赖配置文件设置
   *
   * @param source 原文
   * @param salt 盐
   * @return 哈希结果
   */
  public static String hashWithSalt(String source, String salt) {
    return hashWithSalt(PropKit.get("shiro_hash_algorithm"), source, salt,
        PropKit.getInt("shiro_hash_iterations"));
  }

  private static String genSalt(String user) {
    return PropKit.get("project_name") + SEPARATOR + user;
  }

  /**
   * 生成针对配置文件的用户密码密文，依赖的配置属性：
   *
   * <pre>
   *  - shiro_hash_algorithm
   *  - shiro_hash_iterations
   * </pre>
   *
   * @param user 用户名
   * @param pwd 密码原文
   * @return 哈希结果
   */
  public static String hashPassword(String user, String pwd) {
    return hashWithSalt(PropKit.get("shiro_hash_algorithm"), pwd, genSalt(user),
        PropKit.getInt("shiro_hash_iterations"));
  }

  /**
   * 更新用户的权限缓存，重新加载
   * @param username
   */
  public static void clearCached(String username) {
    new myRealm().reloadAuthorizing(username);
  }
}
